package org.wheel.plugins.starter.jdbc.pool.config;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.wheel.plugins.starter.autoconfigure.DynamicDataSourceProperties;

import java.io.IOException;
import java.util.*;

public class YamlConfigLoader implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, PriorityOrdered {

    // 直接使用 LogFactory 创建日志对象，Hutool 会自动检测项目中的日志框架（优先级：Slf4j > Log4j > Logback > JDK Logging）
    private static final Log log = LogFactory.get();

    private Environment environment;

//    public YamlConfigLoader(Environment environment){
//        this.environment = environment;
//    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        try {
            log.trace("开始手动加载和合并YAML配置文件...");

            // 步骤1：合并所有相关配置文件
            Properties mergedConfig = mergeAllYamlConfigs();

            // 步骤2：添加到环境并绑定配置类
            bindAndRegisterConfigurationBeans(registry, mergedConfig);

            log.trace("YAML配置手动加载完成，共合并 {} 个配置项", mergedConfig.size());

        } catch (Exception e) {
            log.error("YAML配置加载失败，尝试降级方案", e);
            fallbackToEnvironmentConfig(registry);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 可选的后续处理
    }

    /**
     * 合并所有相关的YAML配置文件
     */
    public Properties mergeAllYamlConfigs() throws IOException {
        // 获取激活的profiles
        String[] activeProfiles = environment.getActiveProfiles();
        log.trace("当前激活的profiles: {}", Arrays.toString(activeProfiles));

        // 构建配置文件加载列表（按优先级从低到高）
        List<String> configFiles = buildConfigFileList(activeProfiles);

        Properties finalConfig = new Properties();

        // 按顺序加载并合并
        for (String configFile : configFiles) {
            Properties fileConfig = loadSingleYamlFile(configFile);
            if (!fileConfig.isEmpty()) {
                deepMergeProperties(finalConfig, fileConfig);
                log.trace("已合并配置文件: {}, 包含 {} 个配置项", configFile, fileConfig.size());
            }
        }

        return finalConfig;
    }

    /**
     * 构建配置文件加载顺序
     */
    private List<String> buildConfigFileList(String[] activeProfiles) {
        List<String> configFiles = new ArrayList<>();

        // 1. 基础配置（最低优先级）
        configFiles.add("application.yml");

        // 2. Profile-specific配置
        for (String profile : activeProfiles) {
            configFiles.add("application-" + profile + ".yml");
        }

        // 3. 本地开发配置（最高优先级）
//        configFiles.add("application-local.yml");

        log.trace("配置文件加载顺序: {}", configFiles);
        return configFiles;
    }

    /**
     * 加载单个YAML文件
     */
    private Properties loadSingleYamlFile(String configFile) throws IOException {
        Resource resource = new ClassPathResource(configFile);

        if (!resource.exists()) {
            log.trace("配置文件不存在，跳过: {}", configFile);
            return new Properties();
        }

        try {
            YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
            yamlFactory.setResources(resource);
            Properties properties = yamlFactory.getObject();

            if (properties == null) {
                log.trace("配置文件为空: {}", configFile);
                return new Properties();
            }

            log.trace("成功加载配置文件: {}, 包含 {} 个配置项",
                    configFile, properties.size());
            return properties;

        } catch (Exception e) {
            log.warn("加载配置文件失败: {}, 错误: {}", configFile, e.getMessage());
            return new Properties();
        }
    }

    /**
     * 深度合并Properties（支持嵌套结构）
     */
    private void deepMergeProperties(Properties target, Properties source) {
        for (Map.Entry<Object, Object> entry : source.entrySet()) {
            String key = (String) entry.getKey();
            Object sourceValue = entry.getValue();
            Object targetValue = target.get(key);

            // 如果是嵌套的配置结构，需要特殊处理
            // 这里简化处理，实际使用时可以根据需要实现更复杂的合并逻辑
            target.put(key, sourceValue);
        }
    }

    /**
     * 绑定配置类并注册到容器
     */
    public void bindAndRegisterConfigurationBeans(BeanDefinitionRegistry registry, Properties mergedConfig) {
        // 确保环境是可配置的
        if (!(environment instanceof ConfigurableEnvironment)) {
            throw new IllegalStateException("Environment不是ConfigurableEnvironment，无法添加PropertySource");
        }

        ConfigurableEnvironment configurableEnv = (ConfigurableEnvironment) environment;

        // 创建临时PropertySource
        PropertySource<?> tempSource = new PropertiesPropertySource("mergedYamlConfig", mergedConfig);

        // 添加到环境（最高优先级）
        configurableEnv.getPropertySources().addFirst(tempSource);

        // 创建Binder
        Binder binder = new Binder(ConfigurationPropertySources.from(tempSource));

        // 绑定各个配置类
        DynamicDataSourceProperties dataSourceProps = bindDataSourceProperties(binder);
        dataSourceProps.init();
        DaoConfigProperties daoConfigProps = bindDaoConfigProperties(binder);

        // 注册到容器
        registerBeanDefinition(registry, "dynamicDataSourceProperties", dataSourceProps);
        registerBeanDefinition(registry, "daoConfigProperties", daoConfigProps);
    }

    /**
     * 绑定数据源配置
     */
    private DynamicDataSourceProperties bindDataSourceProperties(Binder binder) {
        DynamicDataSourceProperties properties = new DynamicDataSourceProperties();

        BindResult<DynamicDataSourceProperties> result = binder.bind("spring.datasource",
                Bindable.of(DynamicDataSourceProperties.class));

        if (result.isBound()) {
            log.trace("成功绑定数据源配置 DynamicDataSourceProperties");
            return result.get();
        } else {
            log.trace("数据源配置绑定失败，使用默认配置");
            return properties;
        }
    }

    /**
     * 绑定DAO配置
     */
    private DaoConfigProperties bindDaoConfigProperties(Binder binder) {
        DaoConfigProperties properties = new DaoConfigProperties();

        BindResult<DaoConfigProperties> result = binder.bind("system.default.dao",
                Bindable.of(DaoConfigProperties.class));

        if (result.isBound()) {
            log.trace("成功绑定DAO配置 DaoConfigProperties");
            return result.get();
        } else {
            log.trace("DAO配置绑定失败，使用默认配置");
            return properties;
        }
    }

//    private void registerBeanDefinition(BeanDefinitionRegistry registry, String beanName, Object bean) {
//        try {
//            BeanDefinitionBuilder builder = BeanDefinitionBuilder
//                    .genericBeanDefinition(bean.getClass(), () -> bean);
//            builder.setScope(BeanDefinition.SCOPE_SINGLETON);
//
//            registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
//            log.info("成功注册Bean: {}", beanName);
//        } catch (Exception e) {
//            log.error("注册Bean失败: {}, 错误: {}", beanName, e.getMessage());
//        }
//    }

    /**
     * 注册Bean定义到容器
     */
    private void registerBeanDefinition(BeanDefinitionRegistry registry, String beanName, Object bean) {
        if(registry.containsBeanDefinition(beanName) && !(registry.getBeanDefinition(beanName) instanceof GenericBeanDefinition)) {
            log.trace("{} 没有实现 GenericBeanDefinition 接口，跳过注册", beanName);
            return;
        }

        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(bean.getClass());
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        beanDefinition.setInstanceSupplier(() -> bean);
        if(!registry.containsBeanDefinition(beanName)) {
            registry.registerBeanDefinition(beanName, beanDefinition);
        }else{
            GenericBeanDefinition oldBean = (GenericBeanDefinition)registry.getBeanDefinition(beanName);
            if(oldBean.getInstanceSupplier() == null) {
                registry.removeBeanDefinition(beanName);
                registry.registerBeanDefinition(beanName, beanDefinition);
            }
        }
    }

    /**
     * 当主要配置加载失败时的降级方案
     */
    private void fallbackToEnvironmentConfig(BeanDefinitionRegistry registry) {
        log.trace("启用配置加载降级方案");

        // 直接从Environment创建配置对象
//        DynamicDataSourceProperties dataSourceProps = createFallbackDataSourceProperties();
//        DaoConfigProperties daoConfigProps = createFallbackDaoProperties();
//
//        // 使用降级配置注册
//        registerBeanDefinition(registry, "dynamicDataSourceProperties", dataSourceProps);
//        registerBeanDefinition(registry, "daoConfigProperties", daoConfigProps);
    }

    /**
     * 创建降级数据源配置
     */
    private DynamicDataSourceProperties createFallbackDataSourceProperties() {
        DynamicDataSourceProperties props = new DynamicDataSourceProperties();

        // 从Environment获取关键配置
        String url = environment.getProperty("spring.datasource.url");
        String username = environment.getProperty("spring.datasource.username");
        String password = environment.getProperty("spring.datasource.password");

        // 设置默认值或从系统属性获取
        if (url == null) {
            url = "jdbc:h2:mem:fallback;DB_CLOSE_DELAY=-1";
        }

        // 这里应该根据实际情况设置默认值
        // props.setUrl(url);
        // props.setUsername(username);
        // props.setPassword(password);

        log.trace("创建降级数据源配置");
        return props;
    }

    /**
     * 创建降级DAO配置
     */
    private DaoConfigProperties createFallbackDaoProperties() {
        DaoConfigProperties props = new DaoConfigProperties();

        // 设置默认包路径
//        String defaultPackage = environment.getProperty("system.default.dao.base-packages", "com.example.dao");

        // 这里应该根据实际情况设置默认值
        // props.setBasePackages(new String[]{defaultPackage});

        log.trace("创建降级DAO配置");
        return props;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}